package service

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"strings"
	"time"

	"github.com/yourusername/rss-reader-ai/internal/config"
	"github.com/yourusername/rss-reader-ai/internal/model"
	"github.com/yourusername/rss-reader-ai/internal/repository"
)

// =====================================================
// AIService 接口定义
// =====================================================

// AIService AI业务逻辑接口
type AIService interface {
	// GenerateSummary 为单篇文章生成摘要
	GenerateSummary(articleID int64) error

	// BatchGenerateSummaries 批量生成摘要
	BatchGenerateSummaries(limit int) (int, error)

	// RegenerateSummary 重新生成摘要
	RegenerateSummary(articleID int64) error

	// GetPendingCount 获取待生成摘要的文章数
	GetPendingCount() (int64, error)
}

// CozeRequest Coze API 请求结构
type CozeRequest struct {
	Model    string          `json:"model"`
	Messages []CozeMessage   `json:"messages"`
	Stream   bool            `json:"stream"`
}

// CozeMessage Coze API 消息结构
type CozeMessage struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

// CozeResponse Coze API 响应结构
type CozeResponse struct {
	Choices []struct {
		Message struct {
			Content string `json:"content"`
		} `json:"message"`
	} `json:"choices"`
	Error *struct {
		Message string `json:"message"`
		Type    string `json:"type"`
	} `json:"error,omitempty"`
}

// AISummaryResult AI 生成的结果
type AISummaryResult struct {
	Summary string   `json:"summary"`
	Tags    []string `json:"tags"`
}

// =====================================================
// AIService 接口实现
// =====================================================

// aiService AI业务逻辑实现
type aiService struct {
	articleRepo repository.ArticleRepository
	tagRepo     repository.TagRepository
	config      *config.Config
	httpClient  *http.Client
}

// NewAIService 创建AI业务逻辑实例
func NewAIService(
	articleRepo repository.ArticleRepository,
	tagRepo repository.TagRepository,
	cfg *config.Config,
) AIService {
	return &aiService{
		articleRepo: articleRepo,
		tagRepo:     tagRepo,
		config:      cfg,
		httpClient: &http.Client{
			Timeout: 30 * time.Second,
		},
	}
}

// GenerateSummary 为单篇文章生成摘要
func (s *aiService) GenerateSummary(articleID int64) error {
	// 1. 获取文章
	article, err := s.articleRepo.GetByID(articleID)
	if err != nil {
		return fmt.Errorf("获取文章失败: %w", err)
	}

	// 2. 检查是否已有摘要
	if article.HasAISummary() {
		log.Printf("⚠️  文章已有AI摘要,跳过: %s", article.Title)
		return nil
	}

	// 3. 调用 Coze API 生成摘要
	result, err := s.callCozeAPI(article)
	if err != nil {
		log.Printf("❌ 调用AI失败: %s, Error: %v", article.Title, err)
		// 降级策略: 使用原文前200字作为摘要
		return s.useFallbackSummary(article)
	}

	// 4. 保存 AI 摘要
	now := time.Now()
	if err := s.articleRepo.UpdateFields(articleID, map[string]interface{}{
		"ai_summary":      result.Summary,
		"ai_tags":         result.Tags,
		"ai_generated_at": now,
	}); err != nil {
		return fmt.Errorf("保存AI摘要失败: %w", err)
	}

	// 5. 同步标签
	if len(result.Tags) > 0 {
		if err := s.tagRepo.SyncArticleTags(articleID, result.Tags); err != nil {
			log.Printf("⚠️  同步标签失败: %v", err)
			// 标签同步失败不影响摘要生成
		}
	}

	log.Printf("✅ 生成摘要成功: %s", article.Title)
	return nil
}

// BatchGenerateSummaries 批量生成摘要
func (s *aiService) BatchGenerateSummaries(limit int) (int, error) {
	if limit <= 0 {
		limit = 10 // 默认每次处理10篇
	}

	// 1. 获取待生成摘要的文章
	articles, err := s.articleRepo.ListWithoutAISummary(limit)
	if err != nil {
		return 0, fmt.Errorf("获取待处理文章失败: %w", err)
	}

	if len(articles) == 0 {
		log.Printf("📝 没有待生成摘要的文章")
		return 0, nil
	}

	// 2. 逐个生成摘要
	successCount := 0
	for i, article := range articles {
		log.Printf("🔄 处理 [%d/%d]: %s", i+1, len(articles), article.Title)

		if err := s.GenerateSummary(article.ID); err != nil {
			log.Printf("⚠️  生成摘要失败: %v", err)
			continue
		}

		successCount++

		// 避免API限流,添加延迟
		if i < len(articles)-1 {
			time.Sleep(time.Duration(s.config.AI.RequestInterval) * time.Millisecond)
		}
	}

	log.Printf("✅ 批量生成完成: 成功 %d/%d", successCount, len(articles))
	return successCount, nil
}

// RegenerateSummary 重新生成摘要
func (s *aiService) RegenerateSummary(articleID int64) error {
	// 1. 获取文章
	article, err := s.articleRepo.GetByID(articleID)
	if err != nil {
		return fmt.Errorf("获取文章失败: %w", err)
	}

	// 2. 调用 Coze API
	result, err := s.callCozeAPI(article)
	if err != nil {
		return fmt.Errorf("调用AI失败: %w", err)
	}

	// 3. 更新摘要
	now := time.Now()
	if err := s.articleRepo.UpdateFields(articleID, map[string]interface{}{
		"ai_summary":      result.Summary,
		"ai_tags":         result.Tags,
		"ai_generated_at": now,
	}); err != nil {
		return fmt.Errorf("保存AI摘要失败: %w", err)
	}

	// 4. 同步标签
	if len(result.Tags) > 0 {
		if err := s.tagRepo.SyncArticleTags(articleID, result.Tags); err != nil {
			log.Printf("⚠️  同步标签失败: %v", err)
		}
	}

	log.Printf("✅ 重新生成摘要成功: %s", article.Title)
	return nil
}

// GetPendingCount 获取待生成摘要的文章数
func (s *aiService) GetPendingCount() (int64, error) {
	// 使用极大的limit来获取所有待处理文章,然后统计数量
	articles, err := s.articleRepo.ListWithoutAISummary(10000)
	if err != nil {
		return 0, fmt.Errorf("统计待处理文章失败: %w", err)
	}
	return int64(len(articles)), nil
}

// =====================================================
// 私有辅助方法
// =====================================================

// callCozeAPI 调用 Coze API 生成摘要和标签
func (s *aiService) callCozeAPI(article *model.Article) (*AISummaryResult, error) {
	// 1. 构造 Prompt
	prompt := s.buildPrompt(article)

	// 2. 构造请求
	reqBody := CozeRequest{
		Model: s.config.Coze.Model,
		Messages: []CozeMessage{
			{
				Role:    "user",
				Content: prompt,
			},
		},
		Stream: false,
	}

	jsonData, err := json.Marshal(reqBody)
	if err != nil {
		return nil, fmt.Errorf("序列化请求失败: %w", err)
	}

	// 3. 发送 HTTP 请求
	req, err := http.NewRequest("POST", s.config.Coze.Endpoint, bytes.NewBuffer(jsonData))
	if err != nil {
		return nil, fmt.Errorf("创建请求失败: %w", err)
	}

	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer "+s.config.Coze.APIKey)

	// 4. 执行请求
	resp, err := s.httpClient.Do(req)
	if err != nil {
		return nil, fmt.Errorf("请求AI失败: %w", err)
	}
	defer resp.Body.Close()

	// 5. 读取响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, fmt.Errorf("读取响应失败: %w", err)
	}

	// 6. 检查HTTP状态码
	if resp.StatusCode != http.StatusOK {
		return nil, fmt.Errorf("AI返回错误状态码: %d, Body: %s", resp.StatusCode, string(body))
	}

	// 7. 解析响应
	var cozeResp CozeResponse
	if err := json.Unmarshal(body, &cozeResp); err != nil {
		return nil, fmt.Errorf("解析AI响应失败: %w, Body: %s", err, string(body))
	}

	// 8. 检查业务错误
	if cozeResp.Error != nil {
		return nil, fmt.Errorf("AI返回错误: %s", cozeResp.Error.Message)
	}

	if len(cozeResp.Choices) == 0 {
		return nil, fmt.Errorf("AI响应为空")
	}

	// 9. 解析结果
	content := cozeResp.Choices[0].Message.Content
	result, err := s.parseAIResponse(content)
	if err != nil {
		return nil, fmt.Errorf("解析AI结果失败: %w", err)
	}

	return result, nil
}

// buildPrompt 构造 AI Prompt
func (s *aiService) buildPrompt(article *model.Article) string {
	// 获取文章内容(优先使用正文,否则使用描述)
	content := article.Content
	if content == "" {
		content = article.Description
	}

	// 截断过长的内容(最多4000字)
	if len(content) > 4000 {
		content = content[:4000] + "..."
	}

	// 获取现有标签列表 (动态适应用户的订阅内容)
	tagList := s.getExistingTagList()

	prompt := fmt.Sprintf(`请为以下文章生成摘要和标签:

**文章标题**: %s

**文章内容**:
%s

**要求**:
1. 摘要: 100-200字,突出核心内容和要点
2. 标签: 3-5个关键词标签
   - 优先从以下已有标签中选择: %s
   - 如果没有合适的已有标签,可以创建新标签,但要简洁准确(2-6个字)

**返回格式** (必须是JSON格式):
{
  "summary": "这里是摘要内容",
  "tags": ["标签1", "标签2", "标签3"]
}

请直接返回JSON,不要添加任何其他文字。`, article.Title, content, tagList)

	return prompt
}

// getExistingTagList 获取现有标签列表
func (s *aiService) getExistingTagList() string {
	// 从数据库获取所有标签
	tags, err := s.tagRepo.List()
	if err != nil || len(tags) == 0 {
		// 降级: 返回默认标签
		return s.getDefaultTagList()
	}

	// 提取标签名称
	tagNames := make([]string, 0, len(tags))
	for _, tag := range tags {
		tagNames = append(tagNames, tag.Name)
	}

	// 最多显示50个标签 (避免Prompt过长)
	if len(tagNames) > 50 {
		tagNames = tagNames[:50]
	}

	return strings.Join(tagNames, ", ")
}

// getDefaultTagList 获取默认标签列表 (降级策略)
func (s *aiService) getDefaultTagList() string {
	return "技术, 科技, 编程, 后端, 前端, 数据库, AI, 机器学习, 算法, 架构, " +
		"产品, 设计, 管理, 创业, 投资, 财经, 新闻, 生活, 健康, 旅游"
}

// parseAIResponse 解析 AI 返回的 JSON 结果
func (s *aiService) parseAIResponse(content string) (*AISummaryResult, error) {
	// 清理可能的 Markdown 代码块标记
	content = strings.TrimSpace(content)
	content = strings.TrimPrefix(content, "```json")
	content = strings.TrimPrefix(content, "```")
	content = strings.TrimSuffix(content, "```")
	content = strings.TrimSpace(content)

	var result AISummaryResult
	if err := json.Unmarshal([]byte(content), &result); err != nil {
		return nil, fmt.Errorf("JSON解析失败: %w, Content: %s", err, content)
	}

	// 验证结果
	if result.Summary == "" {
		return nil, fmt.Errorf("摘要为空")
	}

	// 过滤空标签
	validTags := make([]string, 0, len(result.Tags))
	for _, tag := range result.Tags {
		tag = strings.TrimSpace(tag)
		if tag != "" {
			validTags = append(validTags, tag)
		}
	}
	result.Tags = validTags

	return &result, nil
}

// useFallbackSummary 使用降级策略生成摘要
func (s *aiService) useFallbackSummary(article *model.Article) error {
	// 使用原文描述的前200字作为摘要
	summary := article.GetShortDescription(200)
	
	now := time.Now()
	if err := s.articleRepo.UpdateFields(article.ID, map[string]interface{}{
		"ai_summary":      summary,
		"ai_generated_at": now,
	}); err != nil {
		return fmt.Errorf("保存降级摘要失败: %w", err)
	}

	log.Printf("⚠️  使用降级策略: %s", article.Title)
	return nil
}
